package com.maimao.order.rabbit;

import com.alibaba.fastjson.JSON;
import com.maimao.model.kill.dto.KillDto;
import com.maimao.model.order.Order;
import com.maimao.model.order.OrderProcessing;
import com.maimao.model.order.enums.OrderProcessingType;
import com.maimao.model.order.enums.OrderStatus;
import com.maimao.order.client.KillClient;
import com.maimao.order.config.RabbitProperties;
import com.maimao.order.mapper.OrderProcessingMapper;
import com.maimao.order.serivce.OrderService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author MaoLin Wang
 * @date 2021/1/18 6:34 下午
 */
@Component
@Slf4j
public class RabbitReceiver {

    public static final int MAX_RETRY_COUNT = 3;
    @Autowired
    private OrderService orderService;


    @Autowired
    private OrderProcessingMapper orderProcessingMapper;

    @Autowired
    private KillClient killClient;


    public static final Map<Long, Integer> countMap = new ConcurrentHashMap<>();

    /**
     * 处理秒杀订单超时未支付
     * <p>@RabbitHandler 接收对象类型消息</p>
     */
    @RabbitHandler
    @RabbitListener(queues = {RabbitProperties.KILL_ORDER_DEAD_QUEUE}, containerFactory = "multiListenerContainer")
    public void processKillOrderDead(Message message, Channel channel) throws Exception {

        KillDto dto = null;
        try {
            String msg = new String(message.getBody());
            dto = JSON.parseObject(msg, KillDto.class);
            log.info("receive kill order dead msg >>>> {}" + dto);
            Order order = orderService.queryOrder(dto.getOrderId());
            //如果事务回滚，则订单未创建成功，但是发送了消息，因此这里order == null ，直接确认即可
            if (order != null && order.getStatus() != null && order.getStatus().equals(OrderStatus.NOT_PAY.getStatus())) {
                orderService.cancelOrder(dto.getOrderId(), order.getUserId());
                log.info("修改订单{}状态为取消---->", msg);
                killClient.killFail(dto);
            } else if (order == null) {
                log.info("无效订单----{},{}，直接确认 ", dto.getOrderId(), null);

            }
            //手动确认
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error(e.getMessage());
            log.error("取消秒杀订单失败");
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
            throw e;
        }

    }

    /**
     * 接受订单过期消息
     */
    @RabbitListener(queues = {"order.dead.queue"}, containerFactory = "multiListenerContainer")
    public void processDead(Message message, Channel channel) throws Exception {
        Long orderId = null;
        try {
            String msg = new String(message.getBody());
            log.info("订单提交消费者接收过期消息===>{}" + msg);
            try {
                orderId = Long.valueOf(msg);
                //1、校验订单是否已经支付，查询该订单的支付状态
                Order order = orderService.queryOrder(orderId);
                //2、如果未支付就把订单取消，修改订单状态
                //如果事务回滚，则订单未创建成功，但是发送了消息，因此这里order == null ，直接确认即可
                if (order != null && order.getStatus() != null && order.getStatus().equals(OrderStatus.NOT_PAY.getStatus())) {
                    orderService.cancelOrder(orderId, order.getUserId());
                    log.info("修改订单{}状态为取消---->", msg);
                } else if (order == null) {
                    log.info("无效订单----{},{}，直接确认 ", orderId, order);

                }
                //手动确认
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            } catch (Exception e) {
                log.error(e.getMessage());
                //其实订单提交这里没必要重试哈,哎,我就想试试,就是玩儿
                //失败，重新入队
                Integer count = RabbitReceiver.countMap
                        .get(orderId);
                if (count == null) {
                    count = 1;
                    countMap.put(orderId, count);
                } else {
                    ++count;
                    if (count > MAX_RETRY_COUNT) {
                        countMap.remove(orderId);
                        log.error("订单消息拒绝,超过重试次数===>{}", orderId);
                        //一般是网络，或者不应出现的编码异常等原因导致，这里应该记录起来，人工介入，然后定时任务定时处理
                        orderProcessingMapper.insert(OrderProcessing.builder().id(orderId).status(OrderProcessingType.UNDO.getStatus()).retryCnt(0).build());
                        return;
                    }
                    countMap.put(orderId, ++count);
                }
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
                log.error("订单消息拒绝===>{},重试第{}次", orderId, count);
                throw e;
            }
        } catch (Exception e) {
            log.info(e.getMessage());
        }
    }
}
